如果添加了Spring Security的依赖,那么web应用默认对所有的HTTP路径(也称为终点,端点,表示API的具体网址)使用'basic'认证。为了给web应用添加方法级别(method-level)的保护,你可以添加@EnableGlobalMethodSecurity
并使用想要的设置,其他信息参考Spring Security Reference。
默认的AuthenticationManager
只有一个用户('user'的用户名和随机密码会在应用启动时以INFO日志级别打印出来),如下:
Using default security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35
注 如果你对日志配置进行微调,确保org.springframework.boot.autoconfigure.security
类别记录日志级别为INFO
,否则默认的密码不会打印出来。
你可以通过设置security.user.password
改变默认密码,这些和其他有用的属性通过SecurityProperties(以"security"为前缀的属性)被外部化了。
默认的安全配置是通过SecurityAutoConfiguration
,SpringBootWebSecurityConfiguration
(用于web安全),AuthenticationManagerConfiguration
(可用于非web应用的认证配置)进行管理的。你可以添加一个@EnableWebSecurity
bean来彻底关掉Spring Boot的默认配置。为了对它进行自定义,你需要使用外部的属性配置和WebSecurityConfigurerAdapter
类型的beans(比如,添加基于表单的登陆)。
想要关闭认证管理的配置,你可以添加一个AuthenticationManager
类型的bean,或在@Configuration
类的某个方法里注入AuthenticationManagerBuilder
来配置全局的AuthenticationManager
。这里有一些安全相关的Spring Boot应用示例可以拿来参考。
在web应用中你能得到的开箱即用的基本特性如下:
AuthenticationManager
bean和一个用户(查看SecurityProperties.User
获取user的属性)。/css/**, /js/**, /images/**
,/webjars/**
和 **/favicon.ico
)。ApplicationEventPublisher
(成功和失败的认证,拒绝访问)。上述所有特性都能通过外部配置(security.*
)打开,关闭,或修改。想要覆盖访问规则而不改变其他自动配置的特性,你可以添加一个注解@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
的WebSecurityConfigurerAdapter
类型的@Bean
。
注 WebSecurityConfigurerAdapter
默认会匹配所有路径,如果不想完全覆盖Spring Boot自动配置的访问规则,你可以精确的配置想要覆盖的路径。
如果添加了spring-security-oauth2
依赖,你可以利用自动配置简化认证(Authorization)或资源服务器(Resource Server)的设置,详情参考Spring Security OAuth 2 Developers Guide。
想要创建一个授权服务器,并授予access tokens,你需要使用@EnableAuthorizationServer
,并提供security.oauth2.client.client-id
和security.oauth2.client.client-secret
配置。
按以上操作后,你就能使用客户端证书创建一个access token,例如:
$ curl client:secret@localhost:8080/oauth/token -d grant_type=password -d username=user -d password=pwd
/token
端点basic形式的认证证书是client-id
和client-secret
,用户证书通常是Spring Security的user详情(Spring Boot中默认是"user"和一个随机的密码)。
想要关闭自动配置,自己配置授权服务器特性,你只需添加一个AuthorizationServerConfigurer
类型的@Bean
。
为了使用access token,你需要一个资源服务器(可以跟授权服务器是同一个)。创建资源服务器很简单,只需要添加@EnableResourceServer
,提供一些配置以允许服务器解码access token。如果应用也是授权服务器,由于它知道如何去解码tokens,所以也就不需要做其他事情。如果你的app是独立的服务,那你就需要给它添加以下可选配置中的某一项:
security.oauth2.resource.user-info-uri
用于/me
资源(例如,PWS的https://uaa.run.pivotal.io/userinfo
)。security.oauth2.resource.token-info-uri
用于token解码端点(例如,PWS的https://uaa.run.pivotal.io/check_token
)。如果user-info-uri
和token-info-uri
都指定了,你可以设置flag筛选出最想要的那个(默认prefer-token-info=true
)。
另外,如果token是JWTs,你可以配置security.oauth2.resource.jwt.key-value
解码它们(key是验签的key)。验签的键值可以是一个对称密钥,也可以是PEM编码的RSA公钥。如果你没有key,并且它是公开的,你可以通过security.oauth2.resource.jwt.key-uri
提供一个下载URI(有一个"value"字段的JSON对象),例如,在PWS平台上:
$ curl https://uaa.run.pivotal.io/token_key
{"alg":"SHA256withRSA","value":"-----BEGIN PUBLIC KEY-----\nMIIBI...\n-----END PUBLIC KEY-----\n"}
注 如果你使用security.oauth2.resource.jwt.key-uri
,授权服务器需要在应用启动时也运行起来,如果找不到key,它将输出warning,并告诉你如何解决。
Google和其他一些第三方身份(identity)提供商对发送给user info端点的请求头中设置的token类型名有严格要求。默认的Bearer
满足大多数提供商要求,如果需要你可以设置security.oauth2.resource.token-type
来改变它。
如果设置了user-info-uri
,资源服务器在内部将使用一个OAuth2RestTemplate
抓取用于认证的用户信息,这是一个id为userInfoRestTemplate
的@Bean
提供的,但你不需要了解这些,只需要用它即可。默认适用于大多数提供商,但偶尔你可能需要添加其他interceptors,或改变request的验证器(authenticator)。想要添加自定义,只需创建一个UserInfoRestTemplateCustomizer
类型的bean —— 它只有单个方法,在bean创建后,初始化前会调用该方法。此处自定义的rest template仅用于内部执行认证。
注 在YAML中设置RSA key时,需要使用管道符分割多行(“|”),记得缩进key value,例如:
security:
oauth2:
resource:
jwt:
keyValue: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC...
-----END PUBLIC KEY-----
为了将web-app放入一个OAuth2客户端,你只需注解@EnableOAuth2Client
,Spring Boot会创建OAuth2ClientContext
和OAuth2ProtectedResourceDetails
,这些是创建OAuth2RestOperations
必需的。Spring Boot不会自动创建该bean,但你自己创建也不费力:
@Bean
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails details) {
return new OAuth2RestTemplate(details, oauth2ClientContext);
}
注 你可能想添加一个限定名(qualifier),因为应用中可能定义多个RestTemplate
。
该配置使用security.oauth2.client.*
作为证书(跟授权服务器使用的相同),此外,它也需要知道授权服务器中认证和token的URIs,例如:
security:
oauth2:
client:
clientId: bd1c0a783ccdd1c9b9e4
clientSecret: 1a9030fbca47a5b2c28e92f19050bb77824b5ad1
accessTokenUri: https://github.com/login/oauth/access_token
userAuthorizationUri: https://github.com/login/oauth/authorize
clientAuthenticationScheme: form
具有该配置的应用在使用OAuth2RestTemplate
时会重定向到GitHub以完成授权,如果已经登陆GitHub,你甚至不会注意到它已经授权过了。那些特殊的凭证(credentials)只在应用运行于8080端口时有效(为了更灵活,在GitHub或其他提供商上注册自己的客户端app)。
在客户端获取access token时,你可以设置security.oauth2.client.scope
(逗号分隔或一个YAML数组)来限制它请求的作用域(scope)。作用域默认是空的,默认值取决于授权服务器,通常依赖于它拥有的客户端在注册时的设置。
注 对security.oauth2.client.client-authentication-scheme
也有设置,默认为"header"(如果你的OAuth2提供商不喜欢header认证,例如Github,你可能需要将它设置为“form”)。实际上,security.oauth2.client.*
属性绑定到一个AuthorizationCodeResourceDetails
实例,所以它的所有属性都可以指定。
注 在一个非web应用中,你仍旧可以创建一个OAuth2RestOperations
,并且跟security.oauth2.client.*
配置关联。在这种情况下,它是一个“client credentials token grant”,如果你使用它的话就需要获取(此处不需要注解@EnableOAuth2Client
或@EnableOAuth2Sso
)。为了防止基础设施定义,只需要将security.oauth2.client.client-id
从配置中移除(或将它设为空字符串)。
OAuth2客户端可用于从提供商抓取用户详情,然后转换为Spring Security需要的Authentication
token。上述提到的资源服务器通过user-info-uri
属性来支持该功能,这是基于OAuth2的单点登陆(SSO)协议最基本的,Spring Boot提供的@EnableOAuth2Sso
注解让它更容易实践。通过添加该注解及端点配置(security.oauth2.client.*
),Github客户端就可以使用/user/
端点保护它的所有资源了:
security:
oauth2:
...
resource:
userInfoUri: https://api.github.com/user
preferTokenInfo: false
由于所有路径默认都处于保护下,也就没有主页展示那些未授权的用户,进而邀请他们去登陆(通过访问/login
路径,或security.oauth2.sso.login-path
指定的路径)。
为了自定义访问规则或保护的路径(这样你就可以添加主页),你可以将@EnableOAuth2Sso
添加到一个WebSecurityConfigurerAdapter
,该注解会包装它,增强需要的地方以使/login
路径工作。例如,这里我们允许未授权的用户访问主页/
,其他的依旧保持默认:
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void init(WebSecurity web) {
web.ignore("/");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests().anyRequest().authenticated();
}
}
如果Actuator处于使用中,你会发现:
AuditEvents
,并发布到AuditService
。ADMIN
,USER
角色。Actuator的安全特性可以通过外部配置属性(management.security.*
)进行修改。为了覆盖应用访问规则但不覆盖actuator的访问规则,你可以添加一个WebSecurityConfigurerAdapter
类型的@Bean
,并注解@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
,如果想覆盖actuator访问规则,则注解@Order(ManagementServerProperties.ACCESS_OVERRIDE_ORDER)
。